﻿using System;
using System.Collections;
using System.Collections.Generic;

using Netbits.Common.Threading;

namespace Netbits.Common.Collections
{
	/// <summary>
	/// Represent a Locked-Enumerator
	/// Before the instance is created a read-lock is entered
	/// If the class is disposed the read-lock was released
	/// </summary>
	/// <typeparam name="T">Type of Item</typeparam>
	public sealed class LockedEnumerator<T> : IEnumerator<T>, IDisposable
	{
		#region Private Variables

		readonly IEnumerator<T> _inner;
		readonly Lock _Lock;

		#endregion

		#region Constructor

		/// <summary>
		/// Create a new instance of this class and enter the read-lock.
		/// </summary>
		/// <param name="Inner_">IEnumerable collection</param>
		/// <param name="Lock_">The Lock-Instance.</param>
		public LockedEnumerator( IEnumerable<T> Inner_, Lock Lock_ )
		{
			if( Inner_ == null )
				throw new ArgumentNullException( "Inner_" );

			if( Lock_ == null )
				throw new ArgumentNullException( "Lock_" );

			Lock_.EnterReadLock();

			_inner = Inner_.GetEnumerator();
			_Lock = Lock_;
		}

		#endregion

		#region Public Properties
		
		/// <summary>
		/// Get the item at the current position in the enumerator
		/// </summary>
		public T Current
		{
			get
			{
				return _inner.Current;
			}
		}

		/// <summary>
		/// Get the item at the current position in the enumerator
		/// </summary>
		object IEnumerator.Current
		{
			get
			{
				return Current;
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Set the next item in the enumerator.
		/// </summary>
		/// <returns></returns>
		public bool MoveNext()
		{
			return _inner.MoveNext();
		}

		/// <summary>
		/// Set the enumerator to the beginning of the list.
		/// </summary>
		public void Reset()
		{
			_inner.Reset();
		}

		#endregion

		#region IDisposable

		/// <summary>
		/// Dispose the enumerator and release the read-lock
		/// </summary>
		public void Dispose()
		{
			_inner.Dispose();
			_Lock.ExitReadLock();
		}

		#endregion
	}
}
